﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using Grain.Crm.DataMigrator.CrmServices;
using Grain.Crm.DataMigrator.Imports;

namespace Grain.Crm.DataMigrator.Infrastructure
{
    public abstract class ValueResolver : IBuildable
    {
        public abstract string Resolve();
        public abstract void Build(Builder builder);
    }

    public class SheetValueResolver : ValueResolver
    {
        public string AttributeDisplayName { get; set; }

        [XmlIgnore]
        public string HeaderRow { get; set; }

        [XmlIgnore]
        public string ContentRow { get; set; }

        protected SheetValueResolver() { }

        public SheetValueResolver(string attributeDisplayName)
        {
            AttributeDisplayName = attributeDisplayName;
        }

        public override void Build(Builder builder)
        {
            builder.Build(this);
        }

        public override string Resolve()
        {
            return ContentRow.GetByHeading(HeaderRow, AttributeDisplayName);
        }
    }

    public class CrmIdResolver : ValueResolver
    {
        public string[] SearchAttribute { get; set; }
        public ValueResolver[] SearchValues { get; set; }
        public string SearchEntity { get; set; }

        protected CrmIdResolver() { }

        public CrmIdResolver(string searchEntity, string[] searchAttribute, ValueResolver[] valueResolvers)
        {
            SearchAttribute = searchAttribute;
            SearchEntity = searchEntity;
            SearchValues = valueResolvers;
        }

        [XmlIgnore]
        public ICrmService Service { get; set; }

        public override string Resolve()
        {
            var searchValues = SearchValues.Select(v => v.Resolve()).ToArray();

            var value = ImportsHelper.GetEntityId(Service, SearchEntity,
                SearchAttribute,
                searchValues);

            if (value != null)
                return value.ToString();

            return null;
        }
        public override void Build(Builder builder)
        {
            builder.Build(this);
        }
    }

    public class ContainerValueResolver: ValueResolver
    {
        public override string Resolve()
        {
            return Container.GetByKey(Key);
        }

        public override void Build(Builder builder)
        {
            builder.Build(this);
        }

        public string Key { get; set; }

        [XmlIgnore()]
        public Container Container { get; set; }
    }

    public class CrmValueResolver : ValueResolver
    {
        public string[] SearchAttributes { get; set; }
        public ValueResolver[] SearchValues { get; set; }
        public string QueryAttribute { get; set; }

        public string SearchEntity { get; set; }

        [XmlIgnore]
        public ICrmService Service { get; set; }

        protected CrmValueResolver() { }

        public CrmValueResolver(string searchEntity, string queryAttribute, string[] searchAttributes, ValueResolver[] valueResolvers)
        {
            SearchAttributes = searchAttributes;
            SearchEntity = searchEntity;
            SearchValues = valueResolvers;
            QueryAttribute = queryAttribute;
        }


        public override string Resolve()
        {
            var searchValues = SearchValues.Select(v => v.Resolve()).ToArray();

            var value = ImportsHelper.GetData(Service, SearchEntity,
                SearchAttributes,
                searchValues, QueryAttribute);

            return value;
        }

        public override void Build(Builder builder)
        {
            builder.Build(this);
        }
    }

    public class ConstantValueResolver : ValueResolver
    {
        protected ConstantValueResolver()
        { }

        public ConstantValueResolver(string value)
        {
            Value = value;
        }

        public string Value { get; set; }
        public override string Resolve()
        {
            return Value;
        }

        public override void Build(Builder builder)
        {
            //do nothing
        }
    }

}
